/* 
 * File:   DataContext.hpp
 * Author: Faisal
 *
 * Created on April 27, 2012, 8:39 PM
 *
 * Description:
 *		Base class that provides the basic features that all connection providers need to implement.
 */

#ifndef HDataContext_DL

#define HDataContext_DL

#include "../include/Shared.hpp"
#include "../Include/DLContract.hpp"
#include "Common\Include\ConnectionSourceName.hpp"
#include "Common\Include\ParameterInfo.hpp"
#include "Common\Include\QueryModifierBase.hpp"
#include "Common\Include\QueryType.hpp"

using std::string;
using std::vector;
using Supetronix::PersistO::Common::ParameterInfo;
using Supetronix::PersistO::Common::ConnectionSourceName;
using Supetronix::PersistO::Common::QueryModifierBase;
using Supetronix::PersistO::Common::QueryType;


namespace Supetronix
{
	namespace PersistO
	{
		namespace DL
		{
			template<class Ins, class Con, class Res, class Sta>
			class DataContext : public Supetronix::PersistO::DL::DLContract
			{
			public:
				/*
				*	Methods
				*/

				//this method provides the singleton feature
				static Ins* getInstance(void)
				{
					/*
					*	ToDO: Implement the memory boundry features of C++11. It's required for singleton implementation on multiprocessor.
					*	http://www.justsoftwaresolutions.co.uk/threading/multithreading-in-c++0x-part-6-double-checked-locking.html
					*/
					static std::unique_ptr<Ins> _ctx;

					//mutex to lock the creation of singleton
					static std::timed_mutex lock;
				
					//instantiate the timed lock but it won't lock the object yet
					std::unique_lock<std::timed_mutex> singleton(lock, std::chrono::milliseconds(10));

					//check if object is null and then lock is acquired
					if ( !_ctx && singleton )
						//double lock verification
						if ( !_ctx )
							_ctx.reset(new Ins());

					return _ctx.get();
				}

				//virthal method that will run the query and return the resultset
				virtual Res* executeQuery(ConnectionSourceName sourceName, QueryType qryType, const string& query, const QueryModifierBase* modifier) = 0;

				//specific data context providers need to implement this method to connect to a data source
				virtual Con* connect(ConnectionSourceName sourceName) = 0;

				//deprecated method. remove it and use the connection definition class for connection information
				std::string getConnectionString() const
				{
					return "Server=" + _serverName +"; User ID=" + _userID + "; Password=" + _password + "; Database=" + _databaseName;
				}

				//deprecated method and use the connection definition now
				void setConnectionParams(ConnectionSourceName sourceName, string serverName, string userID, string password, string databaseName, int minPoolSize = 0, int maxPoolSize = 10)
				{ 
					_serverName = serverName;
					_userID = userID; 
					_password = password; 
					_databaseName = databaseName;
				}

				//deprecated method and use the connection definition now
				//set the connection minimum and maximum connection pool size. If max pool size is zero then it means no connection pooling
				void setConnectionPoolSize(int minPoolSize = 0, int maxPoolSize = 10)
				{
					if (minPoolSize < 0 || maxPoolSize < 0)
						minPoolSize = 0;

					if (maxPoolSize < 0)
						maxPoolSize = 0;

					_minConnPoolSize = minPoolSize;
					_maxConnPoolSize = maxPoolSize;
				}

				//deprecated method and use the connection definition now
				int getMinimumConnectionPoolSize() const
				{
					return _minConnPoolSize;
				}

				//deprecated method and use the connection definition now
				int getMaximumConnectionPoolSize() const
				{
					return _maxConnPoolSize;
				}

			protected:
				virtual std::unique_ptr<Sta> buildQuery(ConnectionSourceName sourceName, const string& query, const QueryModifierBase* modifier) = 0;
				
				// Constructor and Destructor
				virtual ~DataContext() 
				{
					std::cout << "base destructor" << std::endl;
				}

				DataContext() {};

			};

		}
	}
}

#endif